<template>
  <div class="autoform-expression-editor-wrapper">
    <div class="autoform-expression-textarea" ref="codeMirrorRef"></div>
    <div class="autoform-expression-toolbar">
      <span class="autoform-expression-desc">双击选中数据域到公式框</span>
      <el-button size="small" @click="clearCodeMirror" type="danger" plain>
        {{ i18nt("designer.hint.formulaClear") }}
      </el-button>
    </div>
    <div class="autoform-expression-actionbar">
      <div class="expression-form-domain-wrapper">
        <div class="expression-form-domain-header">
          <el-input v-model="domainKeyWord" placeholder="关键字" :suffix-icon="Search">
            <template #prepend>表单字段</template>
          </el-input>
        </div>
        <div class="expression-form-domain-content">
          <div class="expression-form-domain-item" v-for="field in formFieldList" :key="field.key" @click="insertField(field)">
            [{{ field.isSubFormField ? "子表" : field.isSubFormFooterField ? "合计行" : "主表" }}]{{ field.label }}({{ field.name }})
          </div>
        </div>
      </div>
      <div class="expression-operator-wrapper">
        <div class="expression-operator-group" v-for="(operators, group) in operatorWithGroup" :key="group">
          <template v-for="operator in operators" :key="operator.value">
            <el-tooltip v-if="operator.desc" :content="operator.desc" :show-after="500" effect="light" placement="top">
              <div class="expression-operator-item" @click="insertFunction(operator)">{{ operator.label }}</div>
            </el-tooltip>
            <div v-else class="expression-operator-item" @click="insertFunction(operator)">{{ operator.label }}</div>
          </template>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  import { cloneDeep } from "lodash";
  import { Search } from "@element-plus/icons-vue";
  import { basicSetup, EditorView } from "codemirror";
  import { javascript } from "@codemirror/lang-javascript";
  import { EditorState } from "@codemirror/state";
  import i18n from "@/utils/i18n";
  import { getAllFieldWidgets, getAllContainerWidgets } from "@/utils/util";
  import ExpressionUtil from "@/utils/expression-util";
  import { baseTheme, placeholders } from "@/utils/formula-util";

  export default {
    name: "ExpressionEditor",
    mixins: [ i18n ],
    emits: [ "update:modelValue", "change" ],
    props: {
      modelValue: { type: String, default: "" },
      designer: { type: Object, default: () => ({}) },
      ignoredFields: { type: Array, default: () => ([]) },
      simple: { type: Boolean, default: false },
    },
    data() {
      return {
        codeMirror: null,
        expressionText: "",
        domainKeyWord: "",
      }
    },
    computed: {
      Search() {
        return Search;
      },
      operatorWithGroup() {
        const operatorWithGroup = cloneDeep(ExpressionUtil.OPERATOR_WITH_GROUP);
        if (this.simple) {
          Object.keys(operatorWithGroup).forEach((groupName) => {
            if (["relation","logic"].includes(groupName)) {
              delete operatorWithGroup[groupName];
            }
          });
          // operatorWithGroup["calculation"] = operatorWithGroup["calculation"].filter((operator) => operator.value === "+");
        }
        return operatorWithGroup;
        // return cloneDeep(ExpressionUtil.OPERATOR_WITH_GROUP);
      },
      formFieldList() {
        // 数据格式：{ key：value }: { 明细表字段名：明细表字段所属的主表字段名 }
        const subFormFieldNamesMap = {};
        const subFormFooterFieldNamesMap = {};
        const ignoredFieldNames = this.ignoredFields || [];
        const allFields = getAllFieldWidgets(this.designer.widgetList).filter((item) => {
          const { name } = item.field.options || {};
          return !ignoredFieldNames.includes(name);
        });
        const allContainers = getAllContainerWidgets(this.designer.widgetList);
        allContainers.forEach((record) => {
          const { name: subFormName } = record.container.options || {};
          if (["sub-form", "grid-sub-form"].includes(record.type)) {
            record.container.widgetList?.forEach((item) => {
              const { name } = item.options || {};
              subFormFieldNamesMap[name] = subFormName;
            });
            record.container.widgetFooterList?.forEach((item) => {
              const { name } = item.options || {};
              subFormFooterFieldNamesMap[name] = subFormName;
            });
          }
        })

        return allFields.map((item) => {
          const { name, label } = item.field.options || {};
          const fieldName = name;
          const isSubFormField = Object.keys(subFormFieldNamesMap).includes(fieldName);
          const isSubFormFooterField = Object.keys(subFormFooterFieldNamesMap).includes(fieldName);
          if (isSubFormField) {
            return { key: item.field.id, name: `${ subFormFieldNamesMap[fieldName] }.${ fieldName }`, label: label, isSubFormField, isSubFormFooterField };
          } else if (isSubFormFooterField) {
            return { key: item.field.id, name: `${ subFormFooterFieldNamesMap[fieldName] }.${ fieldName }`, label: label, isSubFormField, isSubFormFooterField };
          } else {
            return { key: item.field.id, name: fieldName, label: label, isSubFormField, isSubFormFooterField };
          }
        }).filter((item) => {
          if (this.domainKeyWord) {
            return item.name?.includes(this.domainKeyWord) || item.label?.includes(this.domainKeyWord);
          } else {
            return true;
          }
        });
      }
    },
    methods: {
      /**
       * 初始化表单字段表达式编辑器
       */
      init(){
        this.expressionText = this.modelValue || "";
        this.codeMirror = new EditorView({
          state: EditorState.create({
            doc: this.expressionText,
            extensions: [
              basicSetup,
              javascript(),
              [ baseTheme, [], placeholders ],
              // 监听 CodeMirror 编辑器文本值变化
              EditorView.updateListener.of((update) => {
                if (update.docChanged) {
                  this.expressionText = update.state.doc.toString();
                  this.$emit("update:modelValue", this.expressionText);
                  this.$emit("change", this.expressionText);
                }
              })
            ]
          }),
          parent: this.$refs.codeMirrorRef
        });
      },

      /**
       * 插入表单字段
       * @param record
       */
      insertField(record) {
        const insertValue = `\${${ record.name }}`;
        this.codeMirror.dispatch({
          changes: {
            from: this.codeMirror.state.selection.main.head,
            to: this.codeMirror.state.selection.main.head,
            insert: insertValue
          },
          selection: {
            anchor: this.codeMirror.state.selection.main.head + insertValue.length
          },
        });
      },

      /**
       * 插入操作符或函数
       * @param record
       */
      insertFunction(record) {
        const { value: insertValue } = record;
        // 如果以 "()" 结尾则为函数，否则为普通操作符
        const selectionLength = insertValue.endsWith("()") ? (insertValue.length - 1) : insertValue.length; //光标偏移距离
        this.codeMirror.dispatch({
          changes: {
            from: this.codeMirror.state.selection.main.head,
            to: this.codeMirror.state.selection.main.head,
            insert: insertValue
          },
          selection: {
            anchor: this.codeMirror.state.selection.main.head + selectionLength
          },
        });
      },

      /**
       * 清空编辑器文本内容
       */
      clearCodeMirror() {
        this.codeMirror.dispatch({
          changes: {
            from: 0,
            to: this.codeMirror.state.doc.length,
            insert: ""
          }
        });
      },
    }
  }
</script>

<style lang="scss" scoped>
  .autoform-expression-editor-wrapper {
    height: 100%;
    font-size: 14px;
    line-height: 1.5;
    display: flex;
    flex-direction: column;
    overflow: hidden;

    .autoform-expression-textarea {
      width: 100%;
      height: 100px;
      border: 1px solid #e4e7ed;
      box-sizing: border-box;
    }

    .autoform-expression-toolbar {
      margin: 5px 0;
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: space-between;

      .autoform-expression-desc {
        color: #a8abb2;
      }
    }

    .autoform-expression-actionbar {
      flex: 1;
      display: flex;
      flex-direction: row;
      align-items: stretch;
      overflow: hidden;
      gap: 5px;

      .expression-form-domain-wrapper {
        width: 45%;
        display: flex;
        flex-direction: column;
        overflow: auto;
        gap: 5px;

        .expression-form-domain-header {
          :deep() {
            .el-input-group__prepend {
              padding: 0 5px;
            }
          }
        }

        .expression-form-domain-content {
          flex: 1;
          padding: 5px 0;
          border: 1px solid #e4e7ed;
          overflow: auto;

          .expression-form-domain-item {
            padding: 0 5px;

            &:hover {
              background: #d9ecff;
              cursor: pointer;
            }

            &:not(:last-child) {
              margin-bottom: 5px;
            }
          }
        }
      }

      .expression-operator-wrapper {
        flex: 1;
        overflow: auto;

        .expression-operator-group {
          padding: 10px 10px;
          display: flex;
          flex-direction: row;
          align-items: center;
          flex-wrap: wrap;
          gap: 8px;

          &:not(:last-child) {
            border-bottom: 1px solid #e4e7ed;
          }
        }

        .expression-operator-item {
          padding: 0 10px;
          line-height: 1.75;
          background: #f2f6fc;
          border: 1px solid #dcdfe6;
          border-radius: 4px;

          &:hover {
            background: #d9ecff;
            border-color: #409EFF;
            cursor: pointer;
          }
        }
      }
    }
  }
</style>
